from email.policy import default

from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
from odoo import SUPERUSER_ID


# '销售订单增加状态控制（有效、暂停、取消、关闭、完成）
class SaleOrder(models.Model):
    _inherit = 'sale.order'

    @api.depends(
        'write_date', 's_order_suspension', 'state', 'create_date', 'picking_ids',
        'mrp_production_ids', 'sb_workflow_state', 'picking_ids.state', 'delivery_status', 'invoice_status'
    )
    def _compute_status(self):
        """
        計算銷售訂單嘅狀態。
        """
        for rec in self:
            # 1. 最優先判斷：永久性狀態
            # 如果訂單已經係 'closed' 或 'cancelled'，就唔需要再判斷
            if rec.status in ('closed', 'cancelled'):
                continue  # 繼續處理下一筆記錄，唔再改變呢個狀態
            # 2. 高優先級判斷：臨時性或特殊狀態
            # 如果訂單被暫停，狀態就係 'hold'
            if rec.s_order_suspension:
                rec.status = 'hold'
                continue
            # 如果訂單被取消，狀態就係 'cancelled'
            if rec.state == 'cancel':
                rec.status = 'cancelled'
                continue
            # 3. 判斷出貨同發票狀態
            # 如果發票已經完成，狀態係 'invoiced'
            if rec.invoice_status == 'invoiced':
                # rec.status = 'invoiced'
                rec.status = 'completed'
                continue
            # 如果出貨完成，狀態係 'completed'
            if rec.delivery_status == 'full':
                rec.status = 'completed'
                continue
            # 如果部分出貨，狀態係 'part_completed'
            if rec.delivery_status in ('started', 'partial'):
                rec.status = 'part_completed'
                continue
            # 4. 判斷訂單流程狀態
            # 如果訂單未出貨但已經係 'sent' 或 'sale' 狀態，表示可以繼續出貨流程，狀態係 'active'
            if (rec.state in ('sent', 'sale')) and (rec.delivery_status in ('pending', False)):
                rec.status = 'active'
                continue

            if rec.state in ['draft', 'sale'] and rec.sb_workflow_state in ['approval', 'approve']:
                rec.status = 'active'
                continue
            # 以上條件都唔符合，就設為 'draft'
            rec.status = 'draft'

    status = fields.Selection([
        ('draft', 'Draft'),
        ('active', 'Active'),
        ('invoiced', 'Invoiced'),
        ('hold', 'Hold'),
        ('closed', 'Closed'),
        ('completed', 'Completed'),
        ('part_completed', 'Part Completed'),
        ('cancelled', 'Cancelled')
    ], tracking=True, store=True, string='MO State',
        default='draft', compute='_compute_status',
        help='外部更改模块的，关键字段')

    product_tmpl_id = fields.Many2one('product.template', string="Customer part")
    origin_sale_order = fields.Char(help='拆分的源单据')
    link_or_delink = fields.Selection([('link', 'Link'), ('delink', 'Delink')],
                                      default='link',
                                      help='断开/连接工单使用字段')
    is_lock = fields.Boolean(string='Lock or Unlock', default=False, copy=False)
    option_mrp_production_ids = fields.Many2many('mrp.production')
    lock_reason = fields.Html(string='Lock Reason')

    def action_cancel(self):
        if self.is_lock and not self._context.get('ecr_apply', False):
            raise ValidationError(_('Sale order is lock, please unlock。'))
        return super().action_cancel()

    def create_shipping_instructions(self):
        records = self.env['sale.order'].browse(
            self._context.get('active_ids', []))
        for rec in records:
            if rec.is_lock:
                raise ValidationError(_('Sale order is lock, please unlock'))
        return super().create_shipping_instructions()

    @api.constrains('status')
    def constraint_status(self):
        for record in self:
            if record.status == 'cancelled':
                flo = record.sb_workflow_item_ids.filtered(lambda x: x.state in ['wait_forward', 'approval'])
                flo.update({'state': 'no_pass',
                            'user_id': SUPERUSER_ID,
                            'approval_instructions': 'ECR自动拒绝',
                            'approval_time': fields.Datetime.now()})


class SbSaleChange(models.Model):
    _name = 'sb.sale.change'
    _inherit = ['portal.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
    _rec_name = 'name'
    _description = '销售订单更改'

    def _default_name(self):
        return self.env['ir.sequence'].next_by_code('sb.sale.change')

    name = fields.Char(string='Ref', default=_default_name)
    partner_id = fields.Many2one('res.partner', domain="[('code', '!=', False)]", string='Customer')
    product_tmpl_id = fields.Many2one('product.template', string="Customer Part")
    code = fields.Char(string='PN')
    version = fields.Char(string='Version')
    line_ids = fields.One2many('sb.sale.change.line', 'change_id', string='Sale Order')
    is_option = fields.Boolean(default=False, help='控制客户、客户部件不可更改')
    note = fields.Text(string='Note')
    state = fields.Selection([('draft', 'Draft'), ('done', 'Done')], string='Status', compute="_compute_state")

    @api.depends('is_option')
    def _compute_state(self):
        for rec in self:
            if rec.is_option:
                rec.state = 'done'
            else:
                rec.state = 'draft'

    @api.onchange('product_tmpl_id')
    def onchange_product_info(self):
        print(self.product_tmpl_id.customer_item_code_ids)
        if not self.product_tmpl_id.customer_item_code_ids:
            return

        customer_item_code_ids = self.product_tmpl_id.customer_item_code_ids
        self.version = customer_item_code_ids[0].version
        self.code = customer_item_code_ids[0].code

    # # 查询客户+物料下 active 状态的销售单
    # @api.onchange('partner_id', 'product_tmpl_id')
    # def onchange_line_ids(self):
    #     self.line_ids = None
    #     if not self.partner_id or not self.product_tmpl_id:
    #         return
    #     objs = self.env['sale.order'].search(
    #         [('status', '=', 'active'),
    #          ('partner_id', '=', self.partner_id.id),
    #          ('product_tmpl_id', '=', self.product_tmpl_id.id)])
    #     line_ids = [(0, 0, {'sale_order_id': o.id,
    #                         'order_line': o.order_line[0].id,
    #                         'price_unit': o.order_line[0].price_unit,
    #                         'planned_receiving_date': o.planned_receiving_date
    #                         }) for o in objs]
    #     self.line_ids = line_ids
    #
    #     if not self.product_tmpl_id.customer_item_code_ids:
    #         return
    #     customer_item_code_ids = self.product_tmpl_id.customer_item_code_ids
    #     self.version = customer_item_code_ids[0].version
    #     self.code = customer_item_code_ids[0].code


class SbSaleChangeLine(models.Model):
    _name = 'sb.sale.change.line'

    change_id = fields.Many2one('sb.sale.change')
    # 销售订单
    sale_order_id = fields.Many2one('sale.order', string='Sale Order')
    # 销售订单行
    order_line = fields.Many2one('sale.order.line', string='Sale Order Line')
    # 交货日期
    commitment_date = fields.Datetime(string="Commitment Date", related='sale_order_id.commitment_date')
    # 计划日期
    planned_receiving_date = fields.Datetime(string='Plan Date', related='sale_order_id.planned_receiving_date')
    # 数量
    qty = fields.Float(string='Qty', related='order_line.product_uom_qty')
    # 新增销售订单的状态, 用来对销售订单进行，取消、暂停、拆分操作
    status = fields.Selection(related='sale_order_id.status', string='Status')
    # 单价
    price_unit = fields.Float('Unit Price', related="order_line.price_unit")
    is_option = fields.Boolean(default=False, help='取消、暂停、拆分一个单据只能操作一遍')
    code = fields.Char(string='PN', related="order_line.pn")
    version = fields.Char(string='PN REV', related="order_line.pn_rev")
    product_id = fields.Many2one('product.product', related="order_line.product_id", string='Product')

    def send_message_port(self, body=""):
        self.change_id.message_post(
            body=body)

    def action_hold(self):
        # 暂停
        if self.sale_order_id.order_line.filtered(lambda x: x.s_mrp_production_ids):
            raise ValidationError(_("Disconnect the open order before executing the suspended sales order."))
        self.sale_order_id.action_suspend_order()
        self.change_id.is_option = True
        self.is_option = True
        self.send_message_port('暂停单据{}'.format(self.sale_order_id.name))
        self._unlock_order()
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'type': 'success',
                'title': _("Hold Sale Order"),
                'message': _("The sales order has been suspended！"),
                'next': {
                    'type': 'ir.actions.act_window_close'
                },
            }
        }

    def action_cancel_hold(self):
        self.sale_order_id.action_cancel_suspend_order()
        self.send_message_port('取消暂停单据{}'.format(self.sale_order_id.name))
        self.change_id.is_option = True
        self.is_option = True
        self._unlock_order()
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'type': 'success',
                'title': _("Cancel Hold Sale Order"),
                'message': _("The sales order hold has been canceled!"),
                'next': {
                    'type': 'ir.actions.act_window_close'
                },
            }
        }

    def action_cancel(self):
        # !!! 取消，取消动作完全依赖，sale_order_id.status == active
        '''
        1 没有MO 直接取消SO
        2 有MO
            提示检查MO状态
            断开 MO-SO连接
            在MO中取消或报废
        '''
        # 检查MO
        self._check_mo()
        # 没有mo，直接取消
        self.sale_order_id.with_context(disable_cancel_warning=True, ecr_apply=True).action_cancel()
        self.change_id.is_option = True
        self.is_option = True
        self.send_message_port('取消单据{}，销售单和出库单已取消'.format(self.sale_order_id.name))
        self._unlock_order()
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'type': 'success',
                'title': _("Cancel Sale Order"),
                'message': _("Sales and invoices have been canceled！"),
                'next': {
                    'type': 'ir.actions.act_window_close'
                },
            }
        }

    def action_split(self):
        # 检查MO
        self._check_mo()
        return {
            'name': _('Split Sale Order'),
            'type': 'ir.actions.act_window',
            'res_model': 'split.order.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'sale_order_id': self.sale_order_id.id,
                'qty': self.qty,
                'change_line_id': self.id
            },
        }

    def _check_mo(self):
        # 若果产生了MO.提示：先断开”MO“ 与 ”SO“之间的连接
        if self.sale_order_id.order_line[0].s_mrp_production_ids:
            raise ValidationError("Please disconnect the connection between MO and SO first.")

    def _unlock_order(self):
        # 解锁销售单、发货的、工单、报废、过数等
        # order_lines = set()
        # picking_ids = set()
        mrp_prods = set()
        # 解锁销售单
        self.sale_order_id.is_lock = False
        order_lines = self.sale_order_id.order_line
        picking_ids = self.sale_order_id.picking_ids
        self.sale_order_id.option_mrp_production_ids.filtered(lambda x: x.is_lock).is_lock = False
        for line in order_lines:
            for mrp in line.s_mrp_production_ids:
                if not mrp_prods:
                    mrp_prods = mrp
                mrp_prods |= self._get_parent_mrp(mrp)
                mrp_prods |= self._get_child_mrp(mrp)
                picking_ids |= mrp.picking_ids

        # 解锁工单
        for mrp in mrp_prods:
            mrp.filtered(lambda x: x.state != 'done').is_lock = False
            # mrp.is_lock = True
        # 解锁picking(出库和生产)
        for picking in picking_ids:
            picking.filtered(lambda x: x.state != 'done').is_lock = False
            # picking.is_lock = True

    def _get_parent_mrp(self, mrp):
        parent_ids = mrp._get_sources()
        # 欠单
        mrp_backorders = mrp.procurement_group_id.mrp_production_ids
        return parent_ids | mrp_backorders | mrp

    def _get_child_mrp(self, mrp):
        child_ids = mrp._get_children()
        # 欠单
        mrp_backorders = mrp.procurement_group_id.mrp_production_ids
        return child_ids | mrp_backorders
